package com.examsystem.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.examsystem.config.SftpConfig;
import com.examsystem.pojo.vo.*;
import com.examsystem.util.JwtUtil;
import com.examsystem.dao.UserMapper;
import com.examsystem.pojo.Paper;
import com.examsystem.pojo.vo.TeacherMsg;
import com.examsystem.pojo.User;
import com.examsystem.service.UserService;
import com.examsystem.util.RedisUtil;
import com.examsystem.util.SftpUtil;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
import static com.examsystem.Const.ConstMsg.*;

/**
 * @author fire'ge
 */
@Service("userServiceImpl")
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Resource
    private AuthenticationManager manager;
    @Resource
    private PasswordEncoder encoder;
    @Resource
    private RedisUtil redisUtil;
    @Value("${websocket.url}")
    String webSocketUrl;



    @Resource
    private RedisTemplate redisTemplate;



        @Override
        public UserMsg getUserMsg ( int userId){
            boolean flag = userMapper.queryUserById(userId) == null;
            if (flag) {
                throw new RuntimeException(CHECK_MSG_FAIL_MSG);
            }
            UserMsg userMsg = userMapper.queryUserMsgByUserId(userId);
            if (userMsg == null) {
                throw new RuntimeException(MSG_NULL_MSG);
            }
            return userMsg;
        }

        @Override
        public User getUser (String phoneNum, String password){
            String pattern = "^(?:(?:\\+|00)86)?1[3-9]\\d{9}$";
            boolean matches = Pattern.matches(pattern, phoneNum);
            if (matches) {
                throw new RuntimeException(PHONE_NUM_FAIL_MSG);
            }
            return userMapper.queryUserByPhoneAndPwd(phoneNum, password);
        }

        @Override
        public User getUserByPhoneNum (String phoneNum){
            return userMapper.queryUserByUsername(phoneNum);
        }

        @Override
        public Result login (User user){

            //将电话号码和密码放入到UsernamePasswordAuthenticationToken来进行封装认证
            UsernamePasswordAuthenticationToken authenticationToken
                    = new UsernamePasswordAuthenticationToken(user.getUserPhoneNum(), user.getUserPassword());
            //对电话号码和密码进行认证,认证成功则返回一个LoginUser,为空则登录失败
            Authentication authenticate = manager.authenticate(authenticationToken);

            if (authenticate == null) {
                throw new RuntimeException("登录失败");
            }
            //将登录状态信息放入到redis中储存
            LoginUser principal = (LoginUser) authenticate.getPrincipal();
            redisUtil.set("login:user" + principal.getUser().getUserId(), principal);
            //封装好状态信息,使用json格式进行返回
            Map<String, String> map = new HashMap<>(5);
            User checkUser = principal.getUser();
            map.put("userId", checkUser.getUserId() + "");
            String token = JwtUtil.getToken(map);
            map.clear();
            map.put("token", token);
            map.put("websocketUrl", webSocketUrl + principal.getUser().getUserId());
            return Result.succ(200, "登陆成功", map);
        }

        @Override
        public int addUser (User user){
            String pattern = "^(?:(?:\\+|00)86)?1[3-9]\\d{9}$";
            String userPhoneNum = user.getUserPhoneNum();
            boolean matches = Pattern.matches(pattern, userPhoneNum);
            if (matches) {
                throw new RuntimeException(PHONE_NUM_FAIL_MSG);
            }
            String userPassword = user.getUserPassword();
            String encode = encoder.encode(userPassword);
            user.setUserPassword(encode);
            return userMapper.addUser(user);
        }

        @Override
        public void updateUserImg ( int userId, String photoUrl){
            boolean flag = userMapper.queryUserById(userId) == null;
            if (flag) {
                throw new RuntimeException(CHECK_MSG_FAIL_MSG);
            }
            int update = userMapper.updateImgByUserId(userId, photoUrl);
            if (update == 0) {
                throw new RuntimeException(ADD_UP_FAIL_MSG);
            }
        }

        @Override
        public List<StuTeacherMsg> queryTeacherMsg (int userId){
            boolean flag = userMapper.queryUserById(userId) == null;
            if (flag) {
                throw new RuntimeException(CHECK_MSG_FAIL_MSG);
            }
            return userMapper.queryStudentsTeacherByUserId(userId);
        }

        @Override
        public String uploadImages (SftpConfig sftpConfig, MultipartFile file,int userId){
            SftpUtil.SftpConfig sftpConfig2 = SftpUtil.sftpConfig();
            String[] split = Objects.requireNonNull(file.getOriginalFilename()).split("\\.");
            String suffix = split[1];
            BeanUtil.copyProperties(sftpConfig, sftpConfig2, CopyOptions.create().ignoreNullValue().ignoreError());
            String fileName = USER_PARAM2 + userId + IMG_PARAM + "." + suffix;
            try {
                SftpUtil.upload(sftpConfig2, "", fileName, file.getInputStream());
            } catch (JSchException | SftpException | IOException e) {
                throw new RuntimeException(e.getMessage());
            }
            return fileName;
        }
        /**
         * 学生登录
         * @param user 用户
         * @return result对象
         */
        @Override
        public Result studentLogin (User user){
            User check = userMapper.queryUserByUsername(user.getUserPhoneNum());
            if (check == null || !Objects.equals(check.getUserIdentity(), STUDENT_RIGHT_CODE)) {
                throw new RuntimeException(ADD_SUCCESS_MSG);
            }
            return login(user);
        }


    /*
        教师端
     */


        /**
         * 教师登录
         * @param user 用户
         * @return result对象
         */
        @Override
        public Result teacherLogin (User user){
            User check = userMapper.queryUserByUsername(user.getUserPhoneNum());
            if (check == null || !Objects.equals(check.getUserIdentity(), TEACHER_RIGHT_CODE)) {
                throw new RuntimeException(ADD_SUCCESS_MSG);
            }
            return login(user);
        }



    @Override
    public User getTeacherMsg(int teacherId) {
        return userMapper.getTeacherMsg(teacherId);
    }


    /**
     * 教师注册
     * @param userPhoneNum 手机
     * @param userPassword 密码
     * @param subject 学科
     * @return 【1：成功   0：失败】
     */
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public int save(String userPhoneNum,String userPassword,String subject,String className) {
        User u1 = userMapper.findUserByPhonePwd(userPhoneNum,userPassword);
        String key = "user: "+userPhoneNum+userPassword+className;
        if (u1 == null) {
            User user1 = userMapper.insertUser(userPhoneNum, userPassword, userMapper.getClassId(className));
            int i = userMapper.addTeacherSubject(user1.getUserId(), subject);
            if (i > 0){
                User user = new User();
                user.setUserPhoneNum(userPhoneNum);
                user.setUserIdentity(userPassword);
                redisTemplate.opsForValue().set(key,user);
                return 1;
            }
        }
        return 0;
    }


    /**
     * 修改教师账号密码
     * @param teacherId  教师id
     * @param password  密码
     */
    @Override
    public Result updatePassword(int teacherId, String password) {
        String encode = encoder.encode(password);
        int i = userMapper.updateTeacherPassword(teacherId, encode);
        if (i >0){
//            redisTemplate.opsForValue().set(, );
            return Result.succ("ok");
        }
        return Result.succ("no");
    }

    /**
     * 获取试卷【根据试卷状态】
     * @param userId  用户id
     * @param choice  【1：待发布  2：已发布】
     * @return  result结果集对象
     */
    @Override
    public Result getPaper(int userId, int choice) {
        Paper paper = null;
        if (choice == NUMBER_1){
            paper = userMapper.getPaper1(userId);
        }else if (choice == NUMBER_2){
            paper = userMapper.getPaper2(userId);
        }
        return Result.succ(paper);
    }
}
